package com.block.account.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.block.account.enums.AccountTypeEnum;
import com.block.account.enums.ActionTypeEnum;
import com.block.account.enums.RecordStatusEnum;
import com.block.account.factory.AccountFactory;
import com.block.account.model.dto.EntryAccountDTO;
import com.block.account.service.IAccountApplyRecordService;
import com.block.account.service.IAccountInfoService;
import com.block.common.annotate.RedisLock;
import com.block.common.constant.AppRspCodeConstant;
import com.block.common.service.LogFactory;
import com.block.common.util.BigDecimalUtil;
import com.block.common.vo.ResponseVo;
import com.block.db.entity.AccountApplyRecord;
import com.block.db.mapper.AccountApplyRecordMapper;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.BigDecimal;

/**
 * <p>
 * 账户入账申请表 服务实现类
 * </p>
 *
 * @author 
 * @since 2023-02-02
 */
@Service
public class AccountApplyRecordServiceImpl extends ServiceImpl<AccountApplyRecordMapper, AccountApplyRecord> implements IAccountApplyRecordService {

    private static Logger log = LogFactory.getCommLog();
    @Autowired
    IAccountInfoService accountInfoService;

    /**
     * 入账申请的确认入账操作
     * @param recordId
     * @param operatorId
     * @param operatorName
     * @return
     */
    @Override
    @RedisLock(lockName = "ENTER::ACCOUNT::RECORD::LOCK::", key = "#recordId")
    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public ResponseVo entryAccount(String recordId, String operatorId, String operatorName) {

        log.info("【申请入账】开始执行【recordId】{}【operatorId】{}【operatorName】{}",
                recordId, operatorId, operatorName);

        AccountApplyRecord applyRecord = this.baseMapper.getEntityByRecordIdLock(recordId);
        if (ObjectUtil.isEmpty(applyRecord) ||
                !ObjectUtil.equals(applyRecord.getStatus(), RecordStatusEnum.WAIT_HANDLE.getValue())){

            log.error("【申请入账】申请信息有误，不可进行入账操作【recordId】{}【operatorId】{}【operatorName】{}",
                    recordId, operatorId, operatorName);
            return new ResponseVo(AppRspCodeConstant.PARAM_ERROR, "入账申请不可操作", "");
        }

        // 判断是否可以进行入账操作
        // 判断一些必须存在的字段是否不为空
        // TODO: 2023/2/8 判断入账信息是否完善（有时间，有需求再做）
        if (ObjectUtil.isEmpty(applyRecord.getImgUrl())){
            return new ResponseVo(AppRspCodeConstant.PARAM_ERROR, "入账图片不能为空", "");
        }
        if (BigDecimalUtil.compare(applyRecord.getBillAmount(), BigDecimal.ZERO) <= 0) {
            return new ResponseVo(AppRspCodeConstant.PARAM_ERROR, "入账金额必须大于0", "");
        }

        // 更新入账申请信息
        AccountApplyRecord updateEntity = new AccountApplyRecord();
        updateEntity.setId(applyRecord.getId());
        updateEntity.setStatus(RecordStatusEnum.SUCCESS.getValue());
        updateEntity.setUpdatorId(operatorId);
        updateEntity.setUpdatorName(operatorName);
        boolean update = this.updateById(updateEntity);
        log.info("【申请入账】更新申请结束【update】{}【recordId】{}", update, recordId);
        if (!update){
            return new ResponseVo(AppRspCodeConstant.ACTION_ERROR, "更新入账申请失败", "");
        }

        // 同步到子账户信息
        EntryAccountDTO entryAccountDTO = new EntryAccountDTO();
        entryAccountDTO.setBillDateInfo(applyRecord.getBillDateInfo());
        entryAccountDTO.setItemAccountId(applyRecord.getItemAccountId());
        entryAccountDTO.setItemAccountType(applyRecord.getItemAccountType());
        entryAccountDTO.setItemAccountKey(applyRecord.getItemAccountKey());
        entryAccountDTO.setItemAccountName(applyRecord.getItemAccountName());

        entryAccountDTO.setActionType(applyRecord.getActionType());

        // 转换金额
        BigDecimal changeAmount = ActionTypeEnum.getRealAmountByActionType(applyRecord.getActionType(), applyRecord.getBillAmount());
        entryAccountDTO.setChangeAmount(changeAmount);

        entryAccountDTO.setExtData(String.valueOf(applyRecord.getId()));
        entryAccountDTO.setOperatorId(operatorId);
        entryAccountDTO.setOperatorName(operatorName);

        // 入账信息
        boolean entryRes = AccountFactory.getService(applyRecord.getItemAccountType())
                .entryAccountInfo(entryAccountDTO);
        log.info("【申请入账】更新子账户信息完成【entryRes】{}【entryAccountDTO】{}",
                entryRes, JSON.toJSONString(entryRes));
        if (!entryRes){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new ResponseVo(AppRspCodeConstant.ACTION_ERROR, "入账失败1，联系管理员", "");
        }

        /**
         * 根据入账审核，获取
         */
        if (ObjectUtil.isNotEmpty(applyRecord.getMainAccountId()) &&
                !StrUtil.equals("0", applyRecord.getMainAccountId())){
            // 操作账户不为空的时候，再进行操作
            EntryAccountDTO mainEntryAccountDTO = new EntryAccountDTO();
            mainEntryAccountDTO.setBillDateInfo(applyRecord.getBillDateInfo());

            mainEntryAccountDTO.setItemAccountId(applyRecord.getMainAccountId());
            mainEntryAccountDTO.setActionType(applyRecord.getActionType());

            // 转换金额
            BigDecimal changeAmount2 = ActionTypeEnum.getMainRealAmountByActionType(applyRecord.getActionType(), applyRecord.getBillAmount());
            mainEntryAccountDTO.setChangeAmount(changeAmount2);

            mainEntryAccountDTO.setExtData(String.valueOf(applyRecord.getId()));
            mainEntryAccountDTO.setOperatorId(operatorId);
            mainEntryAccountDTO.setOperatorName(operatorName);

            // 入账信息
            boolean mainEnterRes = AccountFactory.getService(AccountTypeEnum.ACCOUNT.getValue())
                    .entryAccountInfo(mainEntryAccountDTO);
            log.info("【申请入账】更新子账户信息完成【mainEnterRes】{}【mainEntryAccountDTO】{}",
                    mainEnterRes, JSON.toJSONString(mainEntryAccountDTO));
            if (!mainEnterRes){
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return new ResponseVo(AppRspCodeConstant.ACTION_ERROR, "入账失败2，联系管理员", "");
            }
        }

        return new ResponseVo(AppRspCodeConstant.SUCCESS);
    }

}
